"""
All the functions below are macros in the Creoleparser Sandbox wiki.
Macro names are mapped to each function in the dictionary at the bottom
of this module.
"""
import urllib

import genshi.builder as bldr
import genshi.core
from genshi.filters import HTMLSanitizer
import pygments
import pygments.lexers
import pygments.formatters
import pygments.util
from model import Page
from creoleparser.core import MacroError

sanitizer = HTMLSanitizer()

def title(macro,environ):
    """Return the ``name`` attribute of the page object found in
    ``environ['wiki.metadata_page']``

    """

    return bldr.tag(environ['wiki.metadata_page'].name.replace('_',' '))

def creation_date(macro,environ):
    """Return the ``creation_date`` of the page.body in ``environ['wiki.metadata_page']``    """
    
    return bldr.tag(str(environ['wiki.metadata_page'].body.creation_date))

def include(macro,environ,pagename=None):
    """Return the parsed content of the page identified by arg_string"""
    
    if pagename is None:
        return None
    page_record = Page.get_by_key_name('-'+pagename)
    if page_record is not None:
        # infinit recursion protection
        if ('include',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id) in environ['wiki.recurse']:
            return bldr.tag.div("<<include %s>> stopped, possible infite \
recursion encountered" % macro.arg_string.strip())
        environ['wiki.recurse'].add(('include',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id))
        environ = environ.copy()
        environ['wiki.metadata_page'] = page_record
        environ['wiki.page'] = page_record
        return environ['wiki.parser'].generate(page_record.body.value,environ=environ)


def transclude(macro,environ,pagename=None):
    """Works like ``include`` except that ``environ[metadata_page]`` is set to
       the calling page.

    """

    if pagename is None:
        return None
    page_record = Page.get_by_key_name('-'+pagename)
    if page_record is not None:
        # infinit recursion protection
        if ('transclude',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id) in environ['wiki.recurse']:
            return bldr.tag.div("<<transclude%s>> stopped, possible infite \
recursion encountered" % macro.arg_string)
        environ['wiki.recurse'].add(('transclude',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id))
        environ = environ.copy()
        environ['wiki.metadata_page'] = environ['wiki.page'] 
        environ['wiki.page'] = page_record
        return environ['wiki.parser'].generate(page_record.body.value,environ=environ)


def include_raw(macro,page,pagename=None):
    """Return the raw text of the page identified by arg_string, rendered
    in a <pre> block.

    """

    if pagename is None:
        return None
    page = Page.get_by_key_name('-'+pagename)
    if page is not None:
        return bldr.tag.pre(page.body.value,class_='plain')


def include_source(macro,environ,pagename=None,*pos,**kw):
    """Return the parsed text of the page identified by arg_string, rendered
    in a <pre> block.

    """

    if pagename is None:
        return None
    page_record = Page.get_by_key_name('-'+pagename)
    if page_record is not None:
        # infinit recursion protection
        if ('include-source',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id) in environ['wiki.recurse']:
            return bldr.tag.div("<<include-source%s>> stopped, possible infite \
recursion encountered" % macro.arg_string)
        environ['wiki.recurse'].add(('include-source',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id))
        environ = environ.copy()
        environ['wiki.page'] = page_record
        environ['wiki.metadata_page'] = page_record 
        return bldr.tag.pre(environ['wiki.parser'].render(page_record.body.value,environ=environ).decode('utf-8'))


def source(macro,environ):
    """Return the parsed text of body, rendered in a <pre> block."""
    
    return bldr.tag.pre(environ['wiki.parser'].render(macro.body,environ=environ).decode('utf-8'))


def pre(macro,environ):
    """Return the raw text of body, rendered in a <pre> block."""
    
    return bldr.tag.pre(macro.body)


def float_div(macro,environ,side='right',style=''):
    """Return the parsed text of body, rendered in a <div> block. The div element
    gets a a style attribute to float the content right or left, based on the
    arg_string.
    
    """
    
    if side not in ('right','left'):
        return None
    return bldr.tag.div(macro.parsed_body(), style='float:'+side+';'+style)



def spreadsheet(macro,environ,key,align=None,range=None,height=300,width=500):
    """Embeds a published Google spreadsheet.

    :param key:    the google spreadsheet key, found in its url
    :param height: height of the enclosing iframe
    :param width:  width of the enclosing iframe
    
    """


    l = [('key',key),('hl','en'),('single','true'),('gid','0'),('output','html'),('widget','true')]
    if range:
        l.append(('range',range))
    query = urllib.urlencode(l)

    src='https://spreadsheets.google.com/pub?'+query

    output = bldr.tag.iframe(width=width,height=height,frameborder='0',src=src)

    if align in ['left','center','right']:
        style = "text-align:%s;" % align
        output = bldr.tag.div(output,style=style)        
    return output


def youtube(macro,environ,movie_id,align=None,size='medium'):
    """
    
    """
    
    dimensions =  {'small':('320','265'),
                   'medium':('425','344'),
                   'large':('480','385'),
                   'x-large':('640','505'),
                  }
     
    if size not in dimensions:
        size = 'medium'
    width = dimensions[size][0]
    height = dimensions[size][1]
    children = []
    children.append(bldr.tag.param(name='movie', value='http://www.youtube.com/v/'+movie_id))
    children.append(bldr.tag.param(name='allowFullScreen', value='true'))
    children.append(bldr.tag.param(name='allowscriptaccess', value='always'))
    children.append(bldr.tag.embed(src='http://www.youtube.com/v/'+movie_id,
                                   type="application/x-shockwave-flash",
                                   allowscriptaccess="always",
                                   allowfullscreen="true",
                                   width=width, height=height))
    output = bldr.tag.object(children, width=width, height=height)
    if align in ['left','center','right']:
        style = "text-align:%s;" % align
        output = bldr.tag.div(output,style=style)        
    return output



def div(macro,environ,class_=None,id=None,style=None):
    """
    
    """
    if style:
        style = ';'.join(sanitizer.sanitize_css(style))
    return bldr.tag.div(macro.parsed_body(), id=id, class_=class_,style=style)

def span(macro,environ,class_=None,id=None,style=None):
    """
    
    """
    
    if style:
        style = ';'.join(sanitizer.sanitize_css(style))
    #contents = environ['wiki.parser'].generate(macro.body,environ=environ,context='inline')
    return bldr.tag.span(macro.parsed_body(), id=id, class_=class_,style=style)


def quote(macro,environ,cite=None):
    """Applies a 'blockquote' or 'q' tag, depending on the context."""
    
    if macro.isblock:
        tag = 'blockquote'
    else:
        tag = 'q'
        
    return bldr.tag.__getattr__(tag)(macro.parsed_body(), cite=cite)


def toc(macro, environ, depth=6):
    try:
        depth = int(depth)
    except ValueError:
        raise MacroError("only integer values allowed for 'depth'")
    depth = depth if (depth > 0 and depth < 7) else 6
    environ.setdefault('toc',depth)
    return bldr.tag.toc().generate()

def code(macro,environ,lang=None):
    """

    """
    
    if not macro.body:
        return None
    if lang:
        if not macro.isblock:
            return None
        try:
            lexer = pygments.lexers.get_lexer_by_name(lang, stripall=True)
        except pygments.util.ClassNotFound:
            return None
    else:
        lexer = None
    if lexer:
        text = pygments.highlight(macro.body, lexer, pygments.formatters.HtmlFormatter())
        output = genshi.core.Markup(text)
    elif macro.isblock:
        output = bldr.tag.pre(macro.body)
    else:
        output = bldr.tag.code(macro.body,style="white-space:pre-wrap", class_="highlight")
    return output

non_bodied_macros = {'include':include,
          'transclude':transclude,
          'include-raw':include_raw,
          'include-source':include_source,
          'title':title,
          'creation-date':creation_date,
          'youtube':youtube,
          'spreadsheet': spreadsheet,
          'toc': toc
          }


bodied_macros = {
          'source':source,
          'pre':pre,
          'float':float_div,
          'div':div,
          'span':span,
          'code':code,
          'quote':quote,
          }
